{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "############## PLEASE RUN THIS CELL FIRST! ###################\n",
    "\n",
    "# import everything and define a test runner function\n",
    "from importlib import reload\n",
    "from helper import run\n",
    "import block\n",
    "import ecc\n",
    "import helper\n",
    "import script\n",
    "import tx"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 1\n",
    "\n",
    "Write the `is_coinbase` method of the `Tx` class.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/tx.py) pass: `tx.py:TxTest:test_is_coinbase`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 1\n",
    "\n",
    "reload(tx)\n",
    "run(tx.TxTest(\"test_is_coinbase\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from io import BytesIO\n",
    "from script import Script\n",
    "stream = BytesIO(bytes.fromhex('4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73'))\n",
    "s = Script.parse(stream)\n",
    "print(s.cmds[2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from io import BytesIO\n",
    "from script import Script\n",
    "from helper import little_endian_to_int\n",
    "stream = BytesIO(bytes.fromhex('5e03d71b07254d696e656420627920416e74506f6f6c20626a31312f4542312f4144362f43205914293101fabe6d6d678e2c8c34afc36896e7d9402824ed38e856676ee94bfdb0c6c4bcd8b2e5666a0400000000000000c7270000a5e00e00'))\n",
    "script_sig = Script.parse(stream)\n",
    "print(little_endian_to_int(script_sig.cmds[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 2\n",
    "\n",
    "Write the `coinbase_height` method for the `Tx` class.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/tx.py) pass: `tx.py:TxTest:test_coinbase_height`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 2\n",
    "\n",
    "reload(tx)\n",
    "run(tx.TxTest(\"test_coinbase_height\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from helper import hash256\n",
    "block_hash = hash256(bytes.fromhex('020000208ec39428b17323fa0ddec8e887b4a7c53b8c0a0a220cfd0000000000000000005b0750fce0a889502d40508d39576821155e9c9e3f5c3157f961db38fd8b25be1e77a759e93c0118a4ffd71d'))[::-1]\n",
    "block_id = block_hash.hex()\n",
    "print(block_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 3\n",
    "\n",
    "Write the `parse` for `Block`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_parse`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 3\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_parse\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 4\n",
    "\n",
    "Write the `serialize` for `Block`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_serialize`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 4\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_serialize\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 5\n",
    "\n",
    "Write the `hash` for `Block`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_hash`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 5\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_hash\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from io import BytesIO\n",
    "from block import Block\n",
    "b = Block.parse(BytesIO(bytes.fromhex('020000208ec39428b17323fa0ddec8e887b4a7c53b8c0a0a220cfd0000000000000000005b0750fce0a889502d40508d39576821155e9c9e3f5c3157f961db38fd8b25be1e77a759e93c0118a4ffd71d')))\n",
    "print('BIP9: {}'.format(b.version >> 29 == 0b001))\n",
    "print('BIP91: {}'.format(b.version >> 4 & 1 == 1))\n",
    "print('BIP141: {}'.format(b.version >> 1 & 1 == 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 6\n",
    "\n",
    "Write the `bip9` method for the `Block` class.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_bip9`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 6\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_bip9\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 7\n",
    "\n",
    "Write the `bip91` method for the `Block` class.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_bip91`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 7\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_bip91\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 8\n",
    "\n",
    "Write the `bip141` method for the `Block` class.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_bip141`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 8\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_bip141\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from helper import hash256\n",
    "block_id = hash256(bytes.fromhex('020000208ec39428b17323fa0ddec8e887b4a7c53b8c0a0a220cfd0000000000000000005b0750fce0a889502d40508d39576821155e9c9e3f5c3157f961db38fd8b25be1e77a759e93c0118a4ffd71d'))[::-1]\n",
    "print('{}'.format(block_id.hex()).zfill(64))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from helper import little_endian_to_int\n",
    "bits = bytes.fromhex('e93c0118')\n",
    "exponent = bits[-1]\n",
    "coefficient = little_endian_to_int(bits[:-1])\n",
    "target = coefficient * 256**(exponent - 3)\n",
    "print('{:x}'.format(target).zfill(64))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from helper import little_endian_to_int\n",
    "proof = little_endian_to_int(hash256(bytes.fromhex('020000208ec39428b17323fa0ddec8e887b4a7c53b8c0a0a220cfd0000000000000000005b0750fce0a889502d40508d39576821155e9c9e3f5c3157f961db38fd8b25be1e77a759e93c0118a4ffd71d')))\n",
    "print(proof < target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 9\n",
    "\n",
    "Write the `bits_to_target` function in `helper.py`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_target`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 9\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_target\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from helper import little_endian_to_int\n",
    "bits = bytes.fromhex('e93c0118')\n",
    "exponent = bits[-1]\n",
    "coefficient = little_endian_to_int(bits[:-1])\n",
    "target = coefficient*256**(exponent-3)\n",
    "difficulty = 0xffff * 256**(0x1d-3) / target\n",
    "print(difficulty)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 10\n",
    "\n",
    "Write the `difficulty` method for `Block`\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_difficulty`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 10\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_difficulty\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 11\n",
    "\n",
    "Write the `check_pow` method for `Block`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/block.py) pass: `block.py:BlockTest:test_check_pow`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 11\n",
    "\n",
    "reload(block)\n",
    "run(block.BlockTest(\"test_check_pow\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from block import Block\n",
    "from helper import TWO_WEEKS\n",
    "last_block = Block.parse(BytesIO(bytes.fromhex('00000020fdf740b0e49cf75bb3d5168fb3586f7613dcc5cd89675b0100000000000000002e37b144c0baced07eb7e7b64da916cd3121f2427005551aeb0ec6a6402ac7d7f0e4235954d801187f5da9f5')))\n",
    "first_block = Block.parse(BytesIO(bytes.fromhex('000000201ecd89664fd205a37566e694269ed76e425803003628ab010000000000000000bfcade29d080d9aae8fd461254b041805ae442749f2a40100440fc0e3d5868e55019345954d80118a1721b2e')))\n",
    "time_differential = last_block.timestamp - first_block.timestamp\n",
    "if time_differential > TWO_WEEKS * 4:\n",
    "    time_differential = TWO_WEEKS * 4\n",
    "if time_differential < TWO_WEEKS // 4:\n",
    "    time_differential = TWO_WEEKS // 4\n",
    "new_target = last_block.target() * time_differential // TWO_WEEKS\n",
    "print('{:x}'.format(new_target).zfill(64))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 12\n",
    "\n",
    "Calculate the new bits given the first and last blocks of this 2016 block difficulty adjustment period:\n",
    "\n",
    "Block 471744:\n",
    "\n",
    "```\n",
    "000000203471101bbda3fe307664b3283a9ef0e97d9a38a7eacd8800000000000000000010c8ab\n",
    "a8479bbaa5e0848152fd3c2289ca50e1c3e58c9a4faaafbdf5803c5448ddb845597e8b0118e43a\n",
    "81d3\n",
    "```\n",
    "\n",
    "Block 473759:\n",
    "\n",
    "```\n",
    "02000020f1472d9db4b563c35f97c428ac903f23b7fc055d1cfc26000000000000000000b3f449\n",
    "fcbe1bc4cfbcb8283a0d2c037f961a3fdf2b8bedc144973735eea707e1264258597e8b0118e5f0\n",
    "0474\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 12\n",
    "\n",
    "from block import Block, TWO_WEEKS\n",
    "from helper import target_to_bits\n",
    "\n",
    "block1_hex = '000000203471101bbda3fe307664b3283a9ef0e97d9a38a7eacd8800000000000000000010c8aba8479bbaa5e0848152fd3c2289ca50e1c3e58c9a4faaafbdf5803c5448ddb845597e8b0118e43a81d3'\n",
    "block2_hex = '02000020f1472d9db4b563c35f97c428ac903f23b7fc055d1cfc26000000000000000000b3f449fcbe1bc4cfbcb8283a0d2c037f961a3fdf2b8bedc144973735eea707e1264258597e8b0118e5f00474'\n",
    "\n",
    "# parse both blocks\n",
    "# get the time differential\n",
    "# if the differential > 8 weeks, set to 8 weeks\n",
    "# if the differential < 1/2 week, set to 1/2 week\n",
    "# new target is last target * differential / 2 weeks\n",
    "# convert new target to bits\n",
    "# print the new bits hex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 13\n",
    "\n",
    "Write the `calculate_new_bits` function in `helper.py`\n",
    "\n",
    "#### Make [this test](/edit/code-ch09/helper.py) pass: `helper.py:HelperTest:test_calculate_new_bits`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 13\n",
    "\n",
    "reload(helper)\n",
    "run(helper.HelperTest(\"test_calculate_new_bits\"))"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
